using System.Collections.Generic;
using System.Xml.Linq;
using Boo.Lang.Compiler.Ast;
using Comdiv.Extensions;
using Comdiv.Model;
using Comdiv.Model.Interfaces;
using Comdiv.Logging;
using Comdiv.Application;
using Comdiv.Persistence;
using Comdiv.Inversion;
using Comdiv.Security.Acl;
using Comdiv.Conversations;
using Comdiv.IO;
using Comdiv.Security;
using System.Linq;

namespace Comdiv.Booxml{
    public class BooxmlGenerator{
        public string Generate(XElement xml){
            var m = new Module{
                                  Namespace = new NamespaceDeclaration(xml.Name.LocalName)
                              };
            foreach (var element in xml.Elements()){
                generateElement(element, m.Globals);
            }
            return m.ToCodeString();
        }
        private Expression getSimplified(string value){
            if (value.like(@"(^\w[\w\d_]*$)"))
            {
                return new ReferenceExpression(value);
            }
            else if (value.like(@"^\d+$"))
            {
                return new IntegerLiteralExpression(value.toInt());
            }
            else return new StringLiteralExpression(value);
        }
        private void generateElement(XElement element, Block block){
            var m = new MacroStatement(element.Name.LocalName);

            block.Add(m);

            if(element.Value.hasContent()){
                generateText(element.Value, m.Body);
            }

            IList<string> skips = new List<string>();
            if(element.Attribute("id")!=null){
                skips.Add("id");
                m.Arguments.Add(getSimplified(element.attr("id")));
                if(element.Attribute("name")!=null){
                    m.Arguments.Add(getSimplified(element.attr("name")));
                    skips.Add("name");
                }
            }

            foreach (var attribute in element.Attributes()){
                if (!skips.Contains(attribute.Name.LocalName)){
                    generateAttribute(attribute, m.Body);
                }
            }
            foreach (var e in element.Elements()){
                generateElement(e,m.Body);
            }

        }

        private void generateAttribute(XAttribute attribute, Block block){
            var exp = new BinaryExpression(BinaryOperatorType.Assign, new ReferenceExpression(attribute.Name.LocalName),
                                           getSimplified(attribute.Value));
            if (attribute.Name.LocalName == "type" || attribute.Name.LocalName == "code")
            {
                ((MacroStatement)block.ParentNode).Arguments.Add(exp);
            }
            else{
                block.Add(exp);
            }
        }

        private void generateText(string value, Block block){
            block.Add(new StringLiteralExpression(value));
        }
    }
}